// Copyright (c) 2011 Xi Minggao <brooks.xi@gmail.com>. All rights reserved.
// Use of this source code is governed by the New BSD License that can be
// found in the LICENSE file.

#include "comm/Kiwii.hxx"
#include "KiwiiServer-internal.hxx"
#include "KiwiiClient-internal.hxx"
#include "net/EventLoop.hxx"
#include "net/EPoll.hxx"
#include "net/Networking.hxx"
#include "comm/Exception.hxx"
#include "comm/Logger.hxx"
#include <cerrno>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <boost/assert.hpp>

using namespace kiwii;
using namespace kiwii::net;
using namespace kiwii::comm;
using namespace boost;

KServerImpl::KServerImpl() : listenfd_(-1), el_(new EventLoop<EPoll>) {
}

void KServerImpl::init(unsigned short port, char const* bindaddr) {
  listenfd_ = createTcpListener(port, bindaddr);
}

void KServerImpl::run() {
  BOOST_ASSERT(listenfd_ >= 0);

  el_->setIOEvent(listenfd_, EV_READABLE, [this](net::EventLoopBase& el, int fd, unsigned int firedEvents) {
      BOOST_ASSERT(fd == listenfd_);
      BOOST_ASSERT(firedEvents & EV_READABLE);
      KIWII_UNUSED(el);

      int connfd = accept(fd, nullptr, nullptr);
      if (connfd < 0) {
	//For why we ignore these errors here, please see 16.6 section of UNP v1 3rd edition
	if(errno == EAGAIN || errno == EWOULDBLOCK 
	   || errno == ECONNABORTED || errno == EPROTO 
	   || errno == EINTR) {
	  return;
	} else {
	  throw Exception("accept():") << errinfo_errno(errno);
	}
      }

      new KClientImpl(connfd, *el_, *this);
    });

  el_->rock();
}


